1 package uba.db.table;
2
3 import java.io.Serializable;
4 import java.util.Collections;
5 import java.util.List;
6 import java.util.Set;
7
8 import org.apache.commons.collections.CollectionUtils;
9 import org.apache.commons.collections.Predicate;
10 import org.apache.commons.collections.SetUtils;
11 import org.apache.commons.lang.builder.EqualsBuilder;
12 import org.apache.commons.lang.builder.HashCodeBuilder;
13
14 import uba.db.column.ColumnSpecification;
15
16 /***
17 * Representa el esquema de una tabla. La diferencias con un
18 * {@link uba.db.relationalmodel.RelationSchema} son:
19 * <ul>
20 * <li>basicamente estan a "niveles" distintos, mientras que un esquema de
21 * relación representa algo lógico, una tabla esta asociada con la información
22 * fisica en disco y por lo tanto brinda la forma de acceder a esa información.</li>
23 * <li>una tabla tiene que tener un nombre (un esquema de relación podria no
24 * tenerlo)</li>
25 * <li>un esquema de tabla contiene además información sobre los constraints
26 * (indices, foreing keys, etc)</i>
27 * <li>los columnas de una tabla tienen que tener un nombre</li>
28 * <li>varios "tipos" de columna podrian mapearse a un mismo dominio de
29 * atributo en un esquema de relacion (por ejemplo CHAR y VARCHAR son Strings)</li>
30 * </ul>
31 *
32 * @version $Revision: 1.3 $
33 */
34 public class TableSchema implements Serializable {
35 private static final long serialVersionUID = 3617571600447583797L;
36
37 private List columnSpecifications;
38 private String tableName;
39 private Set primaryKeyColumns;
40
41 /***
42 * Crea una nueva instancia especificando el nombre que tendrá la tabla, la
43 * definición de cada uno de sus campos y los constraints.
44 *
45 * @param tableName
46 * nombre de la tabla.
47 * @param columnSpecifications
48 * especificación de cada uno de los campos.
49 * @param primaryKeyColumns
50 * colección con la especificacion de los campos que conforman la
51 * clave primaria.
52 */
53 public TableSchema(String tableName, List columnSpecifications, Set primaryKeyColumns)
54 throws InvalidTableNameException, InvalidPrimaryKeyColumnsException {
55 validateTableName(tableName);
56
57 this.tableName = tableName.toLowerCase();
58 this.columnSpecifications = columnSpecifications;
59 this.primaryKeyColumns = primaryKeyColumns;
60
61 validatePrimaryKeys();
62 }
63
64 /***
65 * Este constructor es equivalente a:
66 * TableSchema(tableName, columnSpecifications, <i>conjunto vacio</i>).
67 *
68 * @see #TableSchema(String, List, Set)
69 */
70 public TableSchema(String tableName, List columnSpecifications) {
71 this(tableName, columnSpecifications, SetUtils.EMPTY_SET);
72 }
73
74 private void validateTableName(String name) {
75 if (name == null || name.length() == 0) {
76 throw new InvalidTableNameException();
77 }
78 }
79
80
81 private void validatePrimaryKeys() {
82 if (primaryKeyColumns == null || !allPrimaryKeysContainedInColumnSpecifications()) {
83 throw new InvalidPrimaryKeyColumnsException();
84 }
85 }
86
87 private boolean allPrimaryKeysContainedInColumnSpecifications() {
88 return CollectionUtils.isProperSubCollection(primaryKeyColumns,
89 columnSpecifications);
90 }
91
92 /***
93 * @see java.lang.Object#equals(java.lang.Object)
94 */
95 public boolean equals(Object obj) {
96 return EqualsBuilder.reflectionEquals(this, obj);
97 }
98
99 /***
100 * @see java.lang.Object#hashCode()
101 */
102 public int hashCode() {
103 return HashCodeBuilder.reflectionHashCode(this);
104 }
105
106 /***
107 * Retorna el nombre de la tabla que representa este esquema.
108 *
109 * @return un {@link String} no nulo.
110 */
111 public String tableName() {
112 return tableName;
113 }
114
115 /***
116 * Retorna un conjunto con las especificaciones de columna de esta tabla que
117 * conforman la clave primaria de la tabla.
118 */
119 public Set primaryKeyColumns() {
120 return Collections.unmodifiableSet(primaryKeyColumns);
121 }
122
123 /***
124 * Retorna una lista con las especificaciones de columna que contiene este esquema.
125 */
126 public List columnSpecifications() {
127 return Collections.unmodifiableList(columnSpecifications);
128 }
129
130 /***
131 * @see uba.db.table.TableSchema#containsColumnNamed(java.lang.String)
132 */
133 public boolean containsColumnNamed(final String columnName) {
134 return CollectionUtils.exists(columnSpecifications, new Predicate() {
135 public boolean evaluate(Object columnSpecification) {
136 return ((ColumnSpecification) columnSpecification).name()
137 .equalsIgnoreCase(columnName);
138 }
139 });
140 }
141 }